import { Injectable } from '@nestjs/common';
import * as bcrypt from 'bcryptjs';
import { JwtService } from '@nestjs/jwt';
import { UserService } from '../user/user.service';
import { LoginUserDto, LoginUserResponseDto } from './dto/login-user.dto';
import { User } from '../user/entities/user.entity';
import { uniq } from 'lodash';
import { RedisService } from '../common/services/redis.service';
import { getUserRedisKey } from 'src/common/constant/redisKey';

@Injectable()
export class AuthService {
  constructor(
    private readonly userService: UserService,
    private readonly jwtService: JwtService,
    private readonly redisService: RedisService,
  ) {}

  async validateUser(loginUserDto: LoginUserDto): Promise<any> {
    const user = await this.userService.getDetailByUsername(
      loginUserDto.username,
    );
    if (user && (await bcrypt.compare(loginUserDto.password, user.password))) {
      return user;
    }
    return null;
  }
  async getUserFromRedis(id: number): Promise<User> {
    const user = await this.redisService.get('user:' + id);
    if (user) {
      return JSON.parse(user as string);
    }
    return null;
  }
  async login(user: User): Promise<LoginUserResponseDto> {
    const { id, name, roles } = user;
    const permissions = uniq(
      roles
        .map((role) => role.permissions.map((permission) => permission.code))
        .flat(),
    );
    const returnValue = {
      access_token: this.jwtService.sign(
        {
          id,
          name,
        },
        {
          expiresIn: '365d',
        },
      ),
      id,
      name,
    };
    const redisValue: LoginUserResponseDto = {
      ...returnValue,
      roles: roles.map((role) => role.name),
      permissions,
    };
    await this.saveUserToRedis(redisValue);
    return returnValue;
  }
  async saveUserToRedis(user: LoginUserResponseDto) {
    const redisEndTime = 2 * 60 * 60; // 两个小时
    const redisValue = user;
    redisValue.redisEndTime = Date.now() + redisEndTime * 1000;
    await this.redisService.set(
      getUserRedisKey(redisValue.id),
      JSON.stringify(redisValue),
      redisEndTime
    );
  }
}
